-- 自动宠物赠送 + 自动接受 一体脚本
-- 角色可配置: sender / receiver / both

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")

local LocalPlayer = Players.LocalPlayer

local config = {
	role = "both",           -- 角色: sender(仅发送) / receiver(仅接收) / both(发送接收都做)
	targetPlayer = "lamb199303",  -- 目标玩家名称
	petSlot = 5,              -- 宠物所在快捷栏位置(1-9)
	tradeDistance = 10,       -- 交易距离(单位:游戏单位)
	holdDurationPadding = 0.1, -- 触发提示的额外按住时间(秒)
}

-- 日志记录函数，将信息输出到控制台和日志文件
local function log(msg)
	print("[Gift&Accept] " .. msg)  -- 输出到控制台
	local ok = pcall(function()
		appendfile("gift_and_accept_log.txt", "[Gift&Accept] " .. msg .. "\n")  -- 尝试追加到日志文件
	end)
	-- 如果追加失败，尝试创建新文件
	if not ok then
		pcall(function()
			writefile("gift_and_accept_log.txt", "[[Gift&Accept] " .. msg .. "\n")
		end)
	end
end
-- 防止掉线函数，通过随机按键保持角色活跃
local function jump()
    -- 定义一组按键码(空格键,A,D,S,W等)
    local keys = { 0x20, 0x20, 0x20, 0x20, 0x41, 0x44, 0x53, 0x57 }
    -- 随机选择一个按键
    local randomKey = keys[math.random(1, #keys)]
    -- 使用pcall防止按键函数不存在导致的错误
    pcall(function()
        keypress(randomKey)   -- 按下按键
        task.wait(0.2)        -- 等待0.2秒
        keyrelease(randomKey) -- 释放按键
    end)
end

-- 启动一个后台任务，每60秒执行一次jump函数防止掉线
task.spawn(function()
    -- 每60秒执行一次jump函数
    while task.wait(60) do
        jump()
    end
end)

-- ================== 发 送 端：宠物赠送 ==================

-- 获取目标玩家函数，优先使用配置中的目标玩家，如果没有则使用第二个玩家
local function getTarget()
	-- 尝试查找配置中的目标玩家
	local target = Players:FindFirstChild(config.targetPlayer)
	-- 如果找不到，则使用第二个玩家(第一个是本地玩家)
	if not target and #Players:GetPlayers() > 1 then
		target = Players:GetPlayers()[2]
	end
	return target
end

-- 移动到目标玩家附近的函数
local function moveNear(target)
	-- 检查本地玩家和目标玩家及其角色是否存在
	if not (LocalPlayer.Character and target and target.Character) then return false end
	
	-- 获取本地玩家和目标玩家的人形组件和根部件
	local myHum = LocalPlayer.Character:FindFirstChildOfClass("Humanoid")
	local root = target.Character:FindFirstChild("HumanoidRootPart")
	-- 如果缺少必要组件则返回失败
	if not (myHum and root) then return false end
	
	-- 移动到目标玩家位置
	myHum:MoveTo(root.Position)
	
	-- 等待直到接近目标玩家或超时
	local tries = 0
	while tries < 40 do  -- 最多尝试40次(约8秒)
		tries = tries + 1
		-- 获取本地玩家的根部件
		local meRoot = LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
		-- 检查距离是否在交易范围内
		if meRoot and (meRoot.Position - root.Position).Magnitude <= config.tradeDistance then
			return true  -- 成功接近
		end
		wait(0.2)  -- 等待0.2秒再次检查
	end
	return false  -- 超时未成功接近
end

-- 装备指定快捷栏物品的函数
local function equipHotbar(slot)
	-- 使用pcall防止虚拟输入服务不可用导致的错误
	pcall(function()
		-- 计算快捷栏按键码(1-9对应按键码49-57)
		local key = Enum.KeyCode["One"].Value + (slot - 1)
		-- 按下快捷键
		game:GetService("VirtualInputManager"):SendKeyEvent(true, key, false, game)
		wait(0.05)  -- 短暂延迟
		-- 释放快捷键
		game:GetService("VirtualInputManager"):SendKeyEvent(false, key, false, game)
	end)
	wait(0.4)  -- 等待装备动画完成
end

-- 获取当前宠物的函数
local function getCurrentPet()
	-- 获取本地玩家的角色
	local character = LocalPlayer.Character
	if not character then return nil end
	
	-- 检查角色上是否有已装备的工具(宠物)
	local equippedTool = character:FindFirstChildOfClass("Tool")
	if equippedTool then return equippedTool end
	
	-- 如果角色上没有装备，则在背包中查找
	local backpack = LocalPlayer:FindFirstChild("Backpack")
	if backpack then
		-- 遍历背包中的所有物品
		for _, tool in ipairs(backpack:GetChildren()) do
			-- 检查是否为工具类物品
			if tool:IsA("Tool") then
				-- 定义宠物名称关键词列表
				local petNames = {"Bunny","Lab","Dog","Cat","Bird","Pet","Golden","Dragon","Fox","Bee","Butterfly","Puppy","Kitten"}
				-- 检查工具名称是否包含宠物关键词
				for _, n in ipairs(petNames) do
					if tool.Name:find(n) then return tool end
				end
			end
		end
	end
	
	return nil  -- 未找到宠物
end

-- 查找目标玩家附近的宠物赠送提示
local function findPetGiftPrompt(target)
	-- 检查目标及其角色是否存在
	if not (target and target.Character) then return nil end
	
	-- 获取目标玩家的根部件位置
	local root = target.Character:FindFirstChild("HumanoidRootPart")
	if not root then return nil end
	
	-- 初始化最佳提示和距离变量
	local best, bestDist
	
	-- 遍历工作空间中的所有后代
	for _, d in ipairs(workspace:GetDescendants()) do
		-- 检查是否为接近提示
		if d:IsA("ProximityPrompt") then
			-- 尝试获取提示的父部件
			local ok, part = pcall(function()
				-- 如果父部件是Attachment，则获取Attachment的父部件
				return d.Parent and d.Parent:IsA("Attachment") and d.Parent.Parent or d.Parent
			end)
			
			-- 获取锚点部件和位置
			local anchor = part and part:IsA("BasePart") and part or nil
			local pos = anchor and anchor.Position or nil
			
			-- 如果位置有效且在15单位范围内
			if pos then
				local dist = (pos - root.Position).Magnitude
				if dist <= 15 then
					-- 检查提示文本是否包含"gift"和"pet"
					local at = tostring(d.ActionText):lower()
					if at:match("gift") and at:match("pet") then
						-- 如果是第一个找到的提示或比之前找到的更近，则更新最佳提示
						if not best or dist < bestDist then best, bestDist = d, dist end
					end
				end
			end
		end
	end
	
	return best  -- 返回找到的最佳提示或nil
end

-- 触发接近提示的函数
local function firePrompt(prompt)
	-- 如果提示不存在则返回失败
	if not prompt then return false end
	
	-- 尝试使用fireproximityprompt函数(如果可用)
	if typeof(fireproximityprompt) == "function" then
		-- 使用pcall防止错误
		pcall(function() 
			-- 触发提示，并添加额外的按住时间
			fireproximityprompt(prompt, prompt.HoldDuration + config.holdDurationPadding) 
		end)
		return true
	end
	
	-- 如果fireproximityprompt不可用，则使用InputHold方法
	local ok = pcall(function()
		prompt:InputHoldBegin()  -- 开始按住
		wait((prompt.HoldDuration or 0) + config.holdDurationPadding)  -- 等待必要时间+额外时间
		prompt:InputHoldEnd()    -- 结束按住
	end)
	return ok  -- 返回执行结果
end

-- 赠送宠物的主函数
local function giftPet()
	-- 获取目标玩家
	local target = getTarget()
	if not target then log("❌ 无目标玩家") return end
	
	-- 获取当前宠物
	local pet = getCurrentPet()
	if not pet then log("❌ 未找到宠物") return end
	
	-- 移动到目标附近
	if not moveNear(target) then log("❌ 无法靠近目标") return end
	
	-- 装备指定快捷栏的宠物
	equipHotbar(config.petSlot)
	
	-- 查找宠物赠送提示
	local prompt = findPetGiftPrompt(target)
	if not prompt then log("❌ 未找到宠物赠送提示") return end
	
	-- 触发赠送提示
	if firePrompt(prompt) then log("✅ 已触发赠送") else log("❌ 触发失败") end
end

-- ================== 接 收 端：自动接受 ==================

-- 确保按钮可交互的函数，修复可能被禁用的UI元素
local function ensureInteractable(btn)
	local p = btn
	while p and p:IsA("GuiObject") do
		-- 使用pcall防止UI属性修改出错
		pcall(function()
			p.Visible = true     -- 确保按钮可见
			p.Active = true      -- 确保按钮可点击
			-- 提高ZIndex确保按钮在最前层
			if p.ZIndex and p.ZIndex < 50 then p.ZIndex = 50 end
		end)
		p = p.Parent  -- 向上遍历父级
	end
end

-- 触发按钮所有连接事件的函数
local function fireAllConnections(btn)
	local any = false  -- 标记是否有任何事件被触发
	
	-- 内部函数：触发单个信号连接
	local function fire(signal)
		-- 如果信号不存在则返回
		if not signal then return end
		
		-- 使用pcall防止错误
		pcall(function()
			-- 检查getconnections函数是否可用
			if typeof(getconnections) == "function" then
				-- 获取所有连接
				for _, c in ipairs(getconnections(signal)) do
					pcall(function()
						-- 尝试调用连接函数或触发事件
						if c.Function then c.Function() elseif c.Fire then c:Fire() end
						any = true  -- 标记已触发事件
					end)
				end
			end
		end)
	end
	
	-- 尝试触发按钮的各种事件
	fire(btn.Activated)       -- 激活事件
	fire(btn.MouseButton1Click)  -- 鼠标左键点击事件
	-- 注释掉的事件(备用)
	-- fire(btn.MouseButton1Down)
	-- fire(btn.MouseButton1Up)
	
	return any  -- 返回是否有事件被触发
end

-- 获取礼物通知界面中的接受和拒绝按钮
local function getButtons()
	-- 获取玩家GUI
	local pg = LocalPlayer:FindFirstChild("PlayerGui")
	if not pg then return nil, nil end
	
	-- 查找礼物通知界面
	local gui = pg:FindFirstChild("Gift_Notification")
	if not gui then return nil, nil end
	
	-- 通过多层嵌套查找接受和拒绝按钮
	local f1 = gui:FindFirstChild("Frame"); if not f1 then return nil,nil end
	local g2 = f1:FindFirstChild("Gift_Notification"); if not g2 then return nil,nil end
	local holder = g2:FindFirstChild("Holder"); if not holder then return nil,nil end
	local f2 = holder:FindFirstChild("Frame"); if not f2 then return nil,nil end
	
	-- 返回接受和拒绝按钮
	return f2:FindFirstChild("Accept"), f2:FindFirstChild("Decline")
end

-- 点击按钮的函数，多种方法尝试点击按钮
local function clickButton(btn)
	-- 如果按钮不存在则返回失败
	if not btn then return false end
	
	-- 确保按钮可交互
	ensureInteractable(btn)
	wait(0.05)  -- 短暂延迟
	
	-- 触发所有连接事件
	if fireAllConnections(btn) then return true end
	
	return true  -- 默认返回成功
end

-- 自动接受礼物的函数
local function autoAccept()
	-- 获取接受按钮
	local accept = select(1, getButtons())
	-- 如果按钮存在则点击它
	if accept then clickButton(accept) end
end

-- 设置自动接受礼物的监听器
local function setupAutoAccept()
	-- 等待并获取玩家GUI
	local pg = LocalPlayer:WaitForChild("PlayerGui")
	
	-- 监听GUI子元素添加事件
	pg.ChildAdded:Connect(function(child)
		-- 如果是礼物通知，则延迟接受
		if child.Name == "Gift_Notification" then wait(0.2) autoAccept() end
	end)
	
	-- 监听GUI后代元素添加事件
	pg.DescendantAdded:Connect(function(d)
		-- 如果是接受按钮，则点击它
		if (d:IsA("ImageButton") or d:IsA("TextButton")) and d.Name:lower():match("accept") then
			wait(0.05)
			clickButton(d)
		end
	end)
	
	-- 启动一个后台循环，定期检查并接受礼物
	spawn(function()
		while true do autoAccept() wait(0.6) end
	end)
end

-- =============== 入口与快捷键 ===============

-- 记录脚本加载信息
log("一体化脚本已加载，role=" .. config.role)

-- 根据配置的角色设置功能
if config.role == "sender" or config.role == "both" then
	-- 监听键盘输入事件
	UserInputService.InputBegan:Connect(function(input, gp)
		-- 如果输入被游戏处理则忽略
		if gp then return end
		-- 如果按下P键，则触发赠送宠物功能
		if input.KeyCode == Enum.KeyCode.P then giftPet() end
	end)
	log("P 键：赠送宠物")
end

-- 如果配置为接收端或双向模式，则设置自动接受
if config.role == "receiver" or config.role == "both" then
	setupAutoAccept()
	log("已开启自动接受")
end


